using System.Collections.Generic;
using PathFinding;
using Unity.Collections;
using UnityEngine;

namespace Pathfinding.Editor
{
    public class TerrainScanner : MonoBehaviour
    {
        public float gridSize = 1f;
        public LayerMask obstacleLayer;
        public Transform terrainTransform;

        private Dictionary<PathPolygonId, PNode> nodes;
        private int width;
        private int height;

        void Start()
        {
            ScanTerrain();
        }

        public void ScanTerrain()
        {
            if (terrainTransform == null)
            {
                Debug.LogError("Terrain transform is not assigned.");
                return;
            }

            // 获取地形的边界
            Vector3 bottomLeft = terrainTransform.position;
            Vector3 topRight =
                bottomLeft + new Vector3(terrainTransform.localScale.x, 0, terrainTransform.localScale.z);

            width = Mathf.RoundToInt((topRight.x - bottomLeft.x) / gridSize);
            height = Mathf.RoundToInt((topRight.z - bottomLeft.z) / gridSize);

            nodes = new Dictionary<PathPolygonId, PNode>();

            for (int x = 0; x < width; x++)
            {
                for (int z = 0; z < height; z++)
                {
                    Vector3 worldPosition = new Vector3(bottomLeft.x + x * gridSize, 0, bottomLeft.z + z * gridSize);
                    Ray ray = new Ray(worldPosition + Vector3.up * 1000f, Vector3.down);
                    RaycastHit hit;

                    if (Physics.Raycast(ray, out hit, 2000f))
                    {
                        bool walkable = !hit.collider.CompareTag("Obstacle");
                        PathPolygonId nodeId = new PathPolygonId(x * 10000 + z);
                        PNode node = new PNode(nodeId, walkable);
                        nodes[nodeId] = node;
                    }
                }
            }

            ConnectNodes();
        }

        private void ConnectNodes()
        {
            foreach (var kvp in nodes)
            {
                PNode currentNode = kvp.Value;
                var currentX = currentNode.polygonId.Id / 10000;
                var currentZ = currentNode.polygonId.Id % 10000;

                // 上下左右四个方向
                int[] dx = { -1, 1, 0, 0 };
                int[] dz = { 0, 0, -1, 1 };

                for (int i = 0; i < 4; i++)
                {
                    var newX = currentX + dx[i];
                    var newZ = currentZ + dz[i];
                    PathPolygonId neighborId = new PathPolygonId(newX * 10000 + newZ);

                    if (nodes.ContainsKey(neighborId) && nodes[neighborId].Walkable)
                    {
                        currentNode.Neighbors.Add(neighborId);
                    }
                }
            }
        }

        public PNode GetNode(PathPolygonId id)
        {
            if (nodes.TryGetValue(id, out PNode node))
            {
                return node;
            }

            return null;
        }

        public NativeArray<PNode> GetNeighbours(PathPolygonId id)
        {
            PNode node = GetNode(id);
            if ( node.Neighbors.Length == 0)
            {
                return new NativeArray<PNode>(0, Allocator.TempJob);
            }

            NativeArray<PNode> neighbours = new NativeArray<PNode>(node.Neighbors.Length, Allocator.TempJob);

            for (int i = 0; i < node.Neighbors.Length; i++)
            {
                neighbours[i] = GetNode(node.Neighbors[i]);
            }

            return neighbours;
        }

        private void OnDrawGizmos()
        {
            if (nodes == null)
            {
                return;
            }

            foreach (var kvp in nodes)
            {
                PNode node = kvp.Value;
                Vector3 position = new Vector3(
                    (node.Id / 10000) * gridSize,
                    0,
                    (node.Id % 10000) * gridSize
                ) + terrainTransform.position;

                Gizmos.color = node.Walkable ? Color.green : Color.red;
                Gizmos.DrawWireCube(position, new Vector3(gridSize, 0.1f, gridSize));

                foreach (var neighborId in node.Neighbors)
                {
                    PNode neighbor = GetNode(neighborId);
                    if (neighbor != null)
                    {
                        Vector3 neighborPosition = new Vector3(
                            (neighbor.Id / 10000) * gridSize,
                            0,
                            (neighbor.Id % 10000) * gridSize
                        ) + terrainTransform.position;

                        Gizmos.DrawLine(position, neighborPosition);
                    }
                }
            }
        }
    }
}